/*
 * lock.c
 *
 *  Created on: 2017年5月4日
 *      Author: chenss
 */


#include "io/lock.h"
#include "io.h"
#include "utils.h"
#include "message_queue.h"
#include "ctimer.h"

#include <string.h>

struct IoConfig
{
    Io_t io;
    uint32_t extiLine;
};

static const struct IoConfig _lockInConfigs[] =
{
        {{IO(A, 9)}, EXTI_Line9},
        {{IO(A, 8)}, EXTI_Line8},
        {{IO(B, 15)}, EXTI_Line15},
};

static const Io_t _lockOutIos[] =
{
        {IO(B, 4)},
        {IO(B, 3)},
        {IO(A, 15)},
};

static int _lockInStatus[Lock_Max + 1];
static Ctimer_t _shake;

static void _EXTI8N9N15_Config(void);

void Lock_Init(void)
{
    Lock_t lock;
    GPIO_InitTypeDef GPIO_InitStructure;

    memset(_lockInStatus, 0, sizeof(_lockInStatus));

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    _EXTI8N9N15_Config();

    for(lock = 0; lock <= Lock_Max; lock++)
    {
        GPIO_WriteBit(_lockOutIos[lock].port, _lockOutIos[lock].pin, Bit_RESET);

        _lockInStatus[lock] = (GPIO_ReadInputDataBit(_lockInConfigs[lock].io.port,
                _lockInConfigs[lock].io.pin) == Bit_SET);
    }
}

/**
 * @brief  Configure PA9 PA8 PB15 in interrupt mode
 * @param  None
 * @retval None
 */
static void _EXTI8N9N15_Config(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Enable GPIOC clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);

    /* Enable SYSCFG clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    /* Configure pins as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Configure pins as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource8);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource9);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15);

    EXTI_InitStructure.EXTI_Line = EXTI_Line8 | EXTI_Line9 | EXTI_Line15;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

//    EXTI_InitStructure.EXTI_Line = EXTI_Line9;
//    EXTI_Init(&EXTI_InitStructure);
//
//    EXTI_InitStructure.EXTI_Line = EXTI_Line15;
//    EXTI_Init(&EXTI_InitStructure);

    /* Enable and set EXTI4_15 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

static void _OnShakeEnd(void)
{
    Ctimer_Stop(& _shake);

    Lock_t lock;
    int hw, value;

    for(lock = 0; lock <= Lock_Max; lock++)
    {
        hw = (GPIO_ReadInputDataBit(_lockInConfigs[lock].io.port,
                _lockInConfigs[lock].io.pin) == Bit_SET);

        value = _lockInStatus[lock];
        if(value != hw)
        {
            _lockInStatus[lock] = hw;
            IO_Changed(IO_Lock1 + lock, hw);
        }
    }

    /* Clear the EXTI line pending bit */
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_1].extiLine);
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_2].extiLine);
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_3].extiLine);

    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line8 | EXTI_Line9 | EXTI_Line15;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
}

void Lock_StatusScan(void)
{
    Lock_t lock;
    EXTI_InitTypeDef EXTI_InitStructure;

    for(lock = 0; lock <= Lock_Max; lock++)
    {
        if(EXTI_GetITStatus(_lockInConfigs[lock].extiLine) != RESET)
        {

            EXTI_InitStructure.EXTI_Line = EXTI_Line8 | EXTI_Line9 | EXTI_Line15;
            EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
            EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
            EXTI_InitStructure.EXTI_LineCmd = DISABLE;
            EXTI_Init(&EXTI_InitStructure);
            Ctimer_Start(& _shake, 500, _OnShakeEnd, 0);
            break;
        }
    }

    /* Clear the EXTI line pending bit */
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_1].extiLine);
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_2].extiLine);
    EXTI_ClearITPendingBit(_lockInConfigs[Lock_3].extiLine);
}

void Lock_Set(Lock_t lock, int value)
{
    GPIO_WriteBit(_lockOutIos[lock].port, _lockOutIos[lock].pin, Bit_SET);
    Utils_DelayMs(3000);
    GPIO_WriteBit(_lockOutIos[lock].port, _lockOutIos[lock].pin, Bit_RESET);
}

/**
 * @brief 获取锁的状态
 * @param lock
 * @return 1 表示开
 *         0 表示关
 */
int Lock_Get(Lock_t lock)
{
    return GPIO_ReadInputDataBit(_lockInConfigs[lock].io.port,
            _lockInConfigs[lock].io.pin) == Bit_SET;
}
